#pragma once

template<typename T>
class SmartPtr
{
public:
	SmartPtr(T*ptr=nullptr) :mPtr(ptr) { if (nullptr!=mPtr){ mPtr->retain(); }}
	~SmartPtr() { if (mPtr != nullptr) { mPtr->release(); } }
	T*mPtr;
	T*Release() { if (mPtr != nullptr) { mPtr->release(); }return mPtr; }
	T* operator ->() { return mPtr; }
	T* operator ->() const { return mPtr; }
	T& operator*() {  return *mPtr;}
	bool operator==(T* ptr) { return mPtr == ptr; }
	bool operator!=(T* ptr) { return mPtr != ptr; }
	bool operator==(T* ptr)const{ return mPtr == ptr; }
	bool operator!=(T* ptr)const{ return mPtr != ptr; }
	bool operator==(SmartPtr<T>& r) { return mPtr == r.mPtr; }
	SmartPtr<T>& operator=(SmartPtr<T>&r) {
		if (r.mPtr!=nullptr){
			r.mPtr->retain();
		}
		if (mPtr!=nullptr){
			mPtr->release();
		}
		mPtr = r.mPtr;
		return *this;
	}
	SmartPtr<T>& operator=(const SmartPtr<T>& other) {
		if (this != &other) {
			if (other.mPtr != nullptr) {
				other.mPtr->retain();
			}
			if (mPtr != nullptr) {
				mPtr->release();
			}
			mPtr = other.mPtr;
		}
		return *this;
	}
	SmartPtr<T>& operator=(T* ptr) {
		if (ptr != nullptr) {
			ptr->retain();
		}
		if (mPtr != nullptr)
			mPtr->release();
		mPtr = ptr;
		return *this;
	}
	T* GetReference() { return mPtr; }
	T* GetPtr() { return mPtr; }
	T* GetReference() const { return mPtr; }
	T* GetPtr() const { return mPtr; }
};
template<typename T>
bool operator!=(const T* ptr,const SmartPtr<T>& smartPtr) {
	return ptr != smartPtr.mPtr;
}
template<typename T>
bool operator==(const T* ptr, const SmartPtr<T>& smartPtr) {
	return ptr == smartPtr.mPtr;
}
